﻿// -----------------------------------------------------------------------
// <copyright file="DiddlySquat.cs" company="Diddly Squad">
// </copyright>
// -----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Audio;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Dynamics.Contacts;
using DiddlySquatDataTypes;
using Microsoft.Xna.Framework.Content;

namespace DiddlySquat
{
	/// <summary>
	/// This is the main type for the game
	/// </summary>
	public class DiddlySquat : Game
	{
		#region Public Properties
		public static int ScreenWidth { get; private set; }
		public static int ScreenHeight { get; private set; }
		#endregion

		public Animation PlayerDeathAnimation;
		public static Texture2D PlayerDeathAnimationTex;

		#region Private Properties

		//The screens and the current screen
		private HelpScreen helpScreen;
		private MenuScreen menuScreen;
		private GameScreen gameScreen;
		private CompletedScreen completedScreen;
		private GameOverScreen gameOverScreen;
		private OptionsScreen optionsScreen;
		private SaveScreen saveScreen;
		private LoadScreen loadScreen;
		private CreditScreen creditScreen;
		private Screen currentScreen;

		private double endTimer;

		private MouseState mouseStateCurrent, mouseStatePrevious;
		
		private readonly GraphicsDeviceManager graphics;
		private SpriteBatch batch;
		private KeyboardState state, oldKeyState;
		private readonly World world;

		private CharacterFactory characterFactory;
		private Player hero;

		private List<Enemy> enemies; 

		private Level level;

		private List<Obstacle> obstacles;

		private List<Collectable> collectables;

		private int points;

		// Initialize an array for player, enemies and other objects of that nature
		private List<Projectile> projectiles;
		
		
		// Simple camera controls
		private Matrix view;
		private Vector2 cameraPosition;
		private Vector2 screenCenter;
		private Vector2 oldHeroPosition;

		//Display crosshair
		private Texture2D crosshairTex;
		private Vector2 crosshair;

		// The music played during gameplay
		private Song gameplayMusic;

		private SoundEffect fanfare;

		private List<LevelData> levels;

		private int currentLevel;

		private bool moveToNextLevel;

		private int soundLevel = Constants.DefaultSoundLevel;
		private int musicLevel = Constants.DefaultMusicLevel;

		private float timer;
		private bool isTimerRunning = false;
		private bool isGameRunning = false;

		#endregion

		/// <summary>
		/// Initializes a new instance of the <see cref="DiddlySquat"/> class.
		/// </summary>
		public DiddlySquat()
		{
			this.graphics = new GraphicsDeviceManager(this)
				{
					PreferredBackBufferWidth = Constants.DefaultScreenWidth,
					PreferredBackBufferHeight = Constants.DefaultScreenHeight
				};

			Content.RootDirectory = "Content";

			this.world = new World(Constants.DefaultGravity);
			this.world.ContactManager.PostSolve += PostSolve;
		}

		/// <summary>
		/// Load all of the content.
		/// </summary>
		protected override void LoadContent()
		{

			//Initialize the various screens in the game
			menuScreen = new MenuScreen(this.Content, this.MenuScreenEvent, this.graphics);
			gameScreen = new GameScreen(this.Content, this.GameScreenEvent);
			creditScreen = new CreditScreen(this.Content, this.CreditScreenEvent, this.graphics);
			loadScreen = new LoadScreen(this.Content, this.LoadScreenEvent, this.graphics);
			saveScreen = new SaveScreen(this.Content, this.SaveScreenEvent, this.graphics);
			optionsScreen = new OptionsScreen(this.Content, this.OptionsScreenEvent, this.graphics, this.soundLevel, this.musicLevel);
			helpScreen = new HelpScreen(this.Content, this.HelpScreenEvent, this.graphics);
			completedScreen = new CompletedScreen(this.Content, this.CompletedScreenEvent, this.graphics);
			gameOverScreen = new GameOverScreen(this.Content, this.GameOverScreenEvent, this.graphics);


			ScreenWidth = this.graphics.GraphicsDevice.Viewport.Width;
			ScreenHeight = this.graphics.GraphicsDevice.Viewport.Height;

			//Set the current screen
			currentScreen = menuScreen;

			characterFactory = new CharacterFactory(this.Content, this.world);

			enemies = new List<Enemy>();

			// Points
			points = 0;

			level = new Level(this.Content, this.world);

			levels = level.GetLevels();
			if (levels == null || levels.Count < 1)
				throw new ContentLoadException("No level files found. Please make sure that there are files in Content\\levels folder.");

			this.LoadLevel();

			projectiles = new List<Projectile>();

			// Initialize camera controls
			this.view = Matrix.Identity;
			this.cameraPosition = Vector2.Zero;

			this.screenCenter = new Vector2(ScreenWidth * Constants.PlayerOnCameraWidthRatio,
												ScreenHeight * Constants.PlayerOnCameraHeightRatio);

			this.batch = new SpriteBatch(this.graphics.GraphicsDevice);

			crosshairTex = Content.Load<Texture2D>("crosshair");

			gameplayMusic = Content.Load<Song>("sound/diddlysquatmusic");

			// Start the music right away
			PlayMusic(gameplayMusic);

			fanfare = Content.Load<SoundEffect>("sound/FANFARE");

		}

		/// <summary>
		/// Allows the game to run logic such as updating the world,
		/// checking for collisions, gathering input, and playing audio.
		/// </summary>
		/// <param name="gameTime">Provides a snapshot of timing values.</param>
		protected override void Update(GameTime gameTime)
		{
			//Little cleaning up
			this.RemoveDeadEnemies();
			this.RemoveExcessProjectiles();

            this.world.Step((float)gameTime.ElapsedGameTime.TotalMilliseconds * 0.001f);

			//Check hero and game status
			if (hero.IsDead())
			{
				endTimer += gameTime.ElapsedGameTime.TotalSeconds;

				if (endTimer >= 2)
				{
					currentScreen = gameOverScreen;
					gameOverScreen.Points = this.points;
				}
			}


			if (moveToNextLevel)
			{
				endTimer += gameTime.ElapsedGameTime.TotalSeconds;

				if (endTimer > 3)
				{
					if (currentLevel < levels.Count)
					{
						this.LoadLevel();
						moveToNextLevel = false;
					}
					else
					{
						currentScreen = completedScreen;
						completedScreen.Points = this.points;
					}
				}
			}
			//Handle input (don't handle mouse if in transition between levels)
			HandleKeyboard();
            //if (!moveToNextLevel)
            //{
			HandleMouse();
            //}

            if (currentScreen == gameScreen)
                hero.Update(gameTime);

			isGameRunning = ((currentScreen == gameScreen) && !moveToNextLevel);

			//If game is running - let timer run etc.
			if (isGameRunning)
			{
				if (!isTimerRunning)
				{
					isTimerRunning = true;
				}
				if (timer > 0)
					timer -= (float)gameTime.ElapsedGameTime.TotalSeconds;
				else
					timer = 0;

				//We update the world
                //this.world.Step((float)gameTime.ElapsedGameTime.TotalMilliseconds * 0.001f);

				cameraPosition.X -= (hero.Body.Position.X - oldHeroPosition.X) * Constants.MeterInPixels;
				cameraPosition.Y -= (hero.Body.Position.Y - oldHeroPosition.Y) * Constants.MeterInPixels;
				this.view = Matrix.CreateTranslation(new Vector3(this.cameraPosition - this.screenCenter, 0f))
							*
							Matrix.CreateTranslation(
								new Vector3(this.screenCenter + new Vector2(this.screenCenter.X, this.screenCenter.Y), 0f));

				oldHeroPosition = hero.Body.Position;

                //hero.Update(gameTime);

				foreach (Enemy enemy in enemies)
				{
					enemy.Update(gameTime, hero);
				}
			}

			currentScreen.Update(gameTime);

			base.Update(gameTime);


		}

		/// <summary>
		/// Removes the dead enemies.
		/// </summary>
		private void RemoveDeadEnemies()
		{
			foreach (Enemy enemy in this.enemies.ToArray())
			{
				if (enemy.IsDead())
				{
					if (!enemy.DeathAnimation.Active)
					{
						if (this.world.BodyList.Contains(enemy.Body))
							this.world.RemoveBody(enemy.Body);
						enemies.Remove(enemy);
					}
				}
			}
		}

		/// <summary>
		/// Removes the excess projectiles.
		/// </summary>
		private void RemoveExcessProjectiles()
		{
			while (projectiles.Count > Constants.MaxProjectiles)
			{
				if (this.world.BodyList.Contains(projectiles[0].CircleBody))
				{
					this.world.RemoveBody(projectiles[0].CircleBody);
					projectiles[0].Delete();
					projectiles.RemoveAt(0);
				}
			}
		}

		/// <summary>
		/// Solves collisions.
		/// </summary>
		/// <param name="contact">The contact.</param>
		/// <param name="contactConstraint">The contact constraint.</param>
		private void PostSolve(Contact contact, ContactConstraint contactConstraint)
		{
			if (contact.FixtureB.UserData is Player)
			{
				if (contact.FixtureA.UserData is Collectable)
				{
					var collectable = contact.FixtureA.UserData as Collectable;
					collectable.Delete(this.world);
					this.points++;
				}
				else if (contact.FixtureA.UserData is Exit)
				{
					// How many points is one second?
					if (!moveToNextLevel)
					{
					    this.points += (int)timer;
					    isTimerRunning = false;
					    this.fanfare.Play(0.1f * soundLevel, 0f, 0f);
					    moveToNextLevel = true;
                        this.hero.Exit();
				    }
			    }
		    }
		}

		/// <summary>
		/// This is called when the game should draw itself.
		/// </summary>
		/// <param name="gameTime">Provides a snapshot of timing values.</param>
		protected override void Draw(GameTime gameTime)
		{
			if (currentScreen == gameScreen)
			{
				GraphicsDevice.Clear(Color.CornflowerBlue);

				this.batch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, this.view);

				hero.Draw(batch);
				hero.Weapon.Draw(batch);

				//Draw enemies
				foreach (Enemy enemy in enemies)
				{
					enemy.Draw(batch);
				}

				// Draw obstacles
				foreach (Obstacle obstacle in obstacles)
				{
					obstacle.Draw(batch);
				}

				// Draw collectables
				foreach (Collectable collectable in collectables)
				{
					collectable.Draw(batch);
				}

				// Draw Projectiles
				foreach (Projectile projectile in projectiles)
				{
					projectile.Draw(batch);
				}

				this.batch.End();
			}
			this.batch.Begin();

			if (currentScreen == gameScreen)
			{
				// Display crosshair only in the actual game
				this.batch.Draw(crosshairTex, crosshair, Color.White);
			}

			if (currentScreen == gameScreen || currentScreen == loadScreen) 
			{
				//Draw health counter if game or load screen selected
				this.batch.DrawString(
					Content.Load<SpriteFont>(Constants.HealthFont), "Health: " + hero.Health, Constants.HealthPosition, Color.Black);

				//Draw points counter if game or load screen selected
				this.batch.DrawString(
					Content.Load<SpriteFont>(Constants.HealthFont), "Points: " + this.points, Constants.PointsPosition, Color.Black);

				//Draw timer if game or load screen selected
				this.batch.DrawString(
					Content.Load<SpriteFont>(Constants.HealthFont), "Time bonus: " + (int)timer, Constants.TimerPosition, Color.Black);

				
			}

			currentScreen.Draw(this.batch);

			this.batch.End();

			base.Draw(gameTime);
		}

		/// <summary>
		/// Handles the keyboard.
		/// </summary>
		private void HandleKeyboard()
		{
			state = Keyboard.GetState();

			if (currentScreen == gameScreen)
			{
				// Rotates hero
				// Need to be applied as long as the button is pressed
				if (state.IsKeyDown(Keys.A))
					hero.Move(-1 * Constants.PlayerMoveStrength);

				if (state.IsKeyDown(Keys.D)) hero.Move(Constants.PlayerMoveStrength);

				// Brake
				if (state.IsKeyDown(Keys.S))
				{
					hero.Brake();
				}

				//Jump with W or Space
				if (this.CheckKey(Keys.Space)) hero.Jump();

				if (this.CheckKey(Keys.W)) hero.Jump();

				//Quick Save
				if (this.CheckKey(Keys.F5)) this.Save(Constants.QuickSave);

				//Quick load
				if (this.CheckKey(Keys.F6)) this.Load(Constants.QuickSave);

			}

			if (this.CheckKey(Keys.P) || this.CheckKey(Keys.Escape)) //Pause with ESC or P
			{
				currentScreen = menuScreen;
				menuScreen.IsGamePaused = true;
			}

			this.oldKeyState = state;
		}

		/// <summary>
		/// Handles the mouse.
		/// </summary>
		private void HandleMouse()
		{
			mouseStateCurrent = Mouse.GetState();

			if (Utils.DistanceToTarget(new Vector2(mouseStateCurrent.X, mouseStateCurrent.Y), hero.Body.Position * Constants.MeterInPixels) > hero.Weapon.Sprite.Width)
			{

				crosshair.X = mouseStateCurrent.X;
				crosshair.Y = mouseStateCurrent.Y;

                if (this.hero.IsWeaponAvailable())
                {

                    // Point the weapon towards the crosshair
                    hero.Weapon.TurnToFace(crosshair, cameraPosition);

                    // Move the sprite to the current mouse position when the left button is pressed
                    if (currentScreen == gameScreen)
                    {
                        if ((mouseStateCurrent.LeftButton == ButtonState.Pressed) && (mouseStatePrevious.LeftButton != ButtonState.Pressed))
                        {
                            hero.Weapon.Fire(this.projectiles, this.soundLevel);
                        }
                    }
                }

				mouseStatePrevious = mouseStateCurrent;
			}
		}

		/// <summary>
		/// Plays the background music.
		/// </summary>
		/// <param name="song">The song.</param>
		private void PlayMusic(Song song)
		{
			// Due to the way the MediaPlayer plays music,
			// we have to catch the exception. Music will play when the game is not tethered
			try
			{
				// Play the music
				MediaPlayer.Volume = 0.1f * musicLevel;
				MediaPlayer.Play(song);

				// Loop the currently playing song
				MediaPlayer.IsRepeating = true;
			}
			catch { }
		}

		/// <summary>
		/// Stops the music.
		/// </summary>
		private void StopMusic()
		{
			MediaPlayer.Stop();
		}

		/// <summary>
		/// Fires when the HelpScreen is returning control back to the main game class
		/// </summary>
		/// <param name="obj">The obj.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void HelpScreenEvent(object obj, EventArgs e)
		{
			//Switch to the menu screen
			currentScreen = menuScreen;
		}

		/// <summary>
		/// Fires when the CreditScreen is returning control back to the main game class
		/// </summary>
		/// <param name="obj">The obj.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void CreditScreenEvent(object obj, EventArgs e)
		{
			//Switch to the menu screen
			currentScreen = menuScreen;
		}

		/// <summary>
		/// Fires when the MenuScreen is returning control back to the main game class
		/// </summary>
		/// <param name="obj">The obj.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void MenuScreenEvent(object obj, EventArgs e)
		{
			//Switch to correct screen according to menu selection
			MenuScreen menu = (MenuScreen)obj;
			switch (menu.SelectedMenuItem.MenuItemType)
			{
				case Enums.MenuItemType.New:
					currentScreen = gameScreen;
					break;
				case Enums.MenuItemType.Options:
					currentScreen = optionsScreen;
					break;
				case Enums.MenuItemType.Help:
					currentScreen = helpScreen;
					break;
				case Enums.MenuItemType.Load:
					currentScreen = loadScreen;
					loadScreen.RefreshMenu();
					break;
				case Enums.MenuItemType.Save:
					currentScreen = saveScreen;
					saveScreen.RefreshMenu();
					break;
				case Enums.MenuItemType.Credits:
					currentScreen = creditScreen;
					break;
				case Enums.MenuItemType.Quit:
					this.Exit();
					break;
			}
		}

		/// <summary>
		/// Fires when the GameScreen is returning
		/// </summary>
		/// <param name="obj">The obj.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void GameScreenEvent(object obj, EventArgs e)
		{
			//Switch to the menu screen
			//currentScreen = menuScreen;
		}

		/// <summary>
		/// Fires when the LoadScreen is returning control back to the main game class
		/// </summary>
		/// <param name="obj">The obj.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void LoadScreenEvent(object obj, EventArgs e)
		{
			LoadScreen loadS = (LoadScreen)obj;
			if (loadS.SelectedMenuItem.MenuItemType == Enums.MenuItemType.File)
			{
				//Load the game from save file
				this.Load(loadS.SelectedMenuItem.Filename);
				loadScreen.StatusMessage = Constants.LoadedStatus;
				menuScreen.IsGamePaused = true;
			}
			else
			{
				//Only switch back to menu when back is pressed
				currentScreen = menuScreen;
			}
		}

		/// <summary>
		/// Fires when the SaveScreen is returning control back to the main game class
		/// </summary>
		/// <param name="obj">The obj.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void SaveScreenEvent(object obj, EventArgs e)
		{
			SaveScreen saveS = (SaveScreen)obj;
			if (saveS.SelectedMenuItem.MenuItemType == Enums.MenuItemType.NewSave)
			{
				//Create new save
				this.Save("DiddlySquat_" + String.Format("{0:yyyy-MM-dd_HH-mm-ss}", DateTime.Now) + ".sav");
				saveScreen.RefreshMenu();
				loadScreen.RefreshMenu();
				saveScreen.StatusMessage = Constants.SavedStatus;
			}
			else if (saveS.SelectedMenuItem.MenuItemType == Enums.MenuItemType.File)
			{
				//Overwrite old save
				this.Save(saveS.SelectedMenuItem.Filename, true);
				saveScreen.RefreshMenu();
				loadScreen.RefreshMenu();
				saveScreen.StatusMessage = Constants.SavedStatus;
			}
			else
			{	
				//Only switch back to menu when back is pressed
				currentScreen = menuScreen;
			}
		}

		/// <summary>
		/// Fires when the CompletedScreen is returning control back to the main game class
		/// </summary>
		/// <param name="obj">The obj.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void CompletedScreenEvent(object obj, EventArgs e)
		{
			//Switch to the menu screen
			currentScreen = menuScreen;
			menuScreen.IsGamePaused = false;

			this.currentLevel = 0;
			this.endTimer = 0;
			this.timer = 0;
			this.points = 0;
			levels = level.GetLevels();
			if (levels == null || levels.Count < 1)
				throw new ContentLoadException("No level files found. Please make sure that there are files in Content\\levels folder.");

			this.LoadLevel();
		}

		/// <summary>
		/// Fires when the OptionsScreen is returning control back to the main game class
		/// </summary>
		/// <param name="obj">The obj.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void OptionsScreenEvent(object obj, EventArgs e)
		{
			//Set all available game options
			OptionsScreen options = (OptionsScreen)obj;
			this.soundLevel = options.SoundLevel;
			this.musicLevel = options.MusicLevel;
			
			//Reset music for applying new level
			this.StopMusic();
			this.PlayMusic(gameplayMusic);
			
			//Back to game
			currentScreen = menuScreen;
		}

		/// <summary>
		/// Fires when the GameOverScreen is returning control back to the main game class
		/// </summary>
		/// <param name="obj">The obj.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void GameOverScreenEvent(object obj, EventArgs e)
		{
			//Switch to the menu screen
			currentScreen = menuScreen;
			menuScreen.IsGamePaused = false;

			this.currentLevel = 0;
			this.endTimer = 0;
			this.timer = 0;
			this.points = 0;
			levels = level.GetLevels();
			if (levels == null || levels.Count < 1)
				throw new ContentLoadException("No level files found. Please make sure that there are files in Content\\levels folder.");

			this.LoadLevel();
		}

		/// <summary>
		/// Saves the game with specified filename.
		/// </summary>
		/// <param name="filename">The filename.</param>
		/// <param name="overWrite">if set to <c>true</c> [over write].</param>
		private void Save(string filename, bool overWrite = false)
		{
			//Hero and game data
			var save = new SaveGame
				{
					HeroPosition = this.hero.Position,
					Level = this.currentLevel - 1,
					Points = this.points,
					Health = this.hero.Health,
					Timer = this.timer
				};

			//Enemies
			foreach (Enemy enemy in enemies)
			{
				if (!enemy.IsDead()) save.AddEnemyData(enemy.Body.Position.X, enemy.Body.Position.Y, (int)enemy.EnemyType, enemy.Health);
			}

			//Collectables
			foreach (Collectable collectable in collectables)
			{
				save.AddCollectableData(collectable.ObstacleBody.Position.X, collectable.ObstacleBody.Position.Y);
			}

			if (overWrite)
			{
				//Delete existing first
				save.Delete(filename);
				//Then create new filename with current date
				filename = "DiddlySquat_" + String.Format("{0:yyyy-MM-dd_HH-mm-ss}", DateTime.Now) + ".sav";
			}

			save.Save(filename);

			//For generating savegame files
			//this.level.Save(save.GetSaveGame());
		}

		/// <summary>
		/// Loads the game from specified filename.
		/// </summary>
		/// <param name="filename">The filename.</param>
		private void Load(string filename)
		{
			var save = new SaveGame();
			if (save.Load(filename))
			{
				this.LoadLevel(save);
			}

		}

		/// <summary>
		/// Creates the characters.
		/// </summary>
		/// <param name="save">The save.</param>
		private void CreateCharacters(SaveGame save)
		{
			//First clear
			//this.ClearOldCharacters();
			
			//Then reload player
			hero = characterFactory.CreatePlayer(save.HeroPosition, save.Health);
			
			//and enemies
			foreach (EnemyData enemyData in save.Enemies)
			{
				Enemy enemy = characterFactory.CreateEnemy(
					new Vector2(enemyData.X, enemyData.Y), (Enums.EnemyType)(enemyData.EnemyType), enemyData.Health);
				enemies.Add(enemy);
			}
			
			
		}

		/// <summary>
		/// Clears the old characters.
		/// </summary>
		private void ClearOldCharacters()
		{
            //if (this.hero != null)
            //{
            //    //Remove Weapon-Hero joint 
            //    if (this.hero.Joint != null) this.world.RemoveJoint(this.hero.Joint);

            //    if (this.hero != null && this.hero.Weapon != null) this.world.RemoveBody(this.hero.Weapon.Body);

            //    //Remove hold hero first
            //    hero.Kill(false);
            //}
            //foreach (Body body in this.world.BodyList)
            //    this.world.RemoveBody(body);

			//Remove enemies
			if (enemies != null)
			{
                enemies.Clear();
                //for (int i = enemies.Count - 1; i >= 0; i--)
                //{
                //    //enemies[i].Kill(false);
                //    enemies.RemoveAt(i);
                //}
			}

			//Remove projectiles
			if (projectiles != null)
			{
                projectiles.Clear();
                //for (int i = projectiles.Count - 1; i >= 0; i--)
                //{
                //    if (this.world.BodyList.Contains(projectiles[i].CircleBody))
                //    {
                //        //this.world.RemoveBody(projectiles[i].CircleBody);
                //        //projectiles[i].Delete();
						
                //    }
                //    projectiles.RemoveAt(i);
                //}
			}


		}

		/// <summary>
		/// Clears the collectables.
		/// </summary>
		private void ClearCollectables()
		{
			//Remove collectables
			if (collectables != null)
			{
                collectables.Clear();
                //for (int i = collectables.Count - 1; i >= 0; i--)
                //{
                //    //collectables[i].Delete(this.world);
                //    collectables.RemoveAt(i);
                //}
			}
		}

        private void RemoveBodies()
        {
            foreach (Body body in this.world.BodyList)
                this.world.RemoveBody(body);
        }

		/// <summary>
		/// Creates the collectables.
		/// </summary>
		/// <param name="collectableDatas">The collectable datas.</param>
		private void CreateCollectables(List<CollectableData> collectableDatas)
		{
			collectables = new List<Collectable>();
			foreach (CollectableData collectableData in collectableDatas)
			{
				var collectable = new Collectable();
				var collectableSprite = this.Content.Load<Texture2D>(Constants.ObstacleSprite6);
				collectableSprite.Name = Constants.ObstacleSprite6;
				collectable.Initialize(
					this.world,
					collectableData.X,
					collectableData.Y,
					1,
					0,
					collectableSprite,
					Enums.ObstacleType.Collectable);
				this.collectables.Add(collectable);
			}
		}

		/// <summary>
		/// Loads the level initially.
		/// </summary>
		private void LoadLevel()
		{
            this.RemoveBodies();
            this.ClearOldCharacters();
			
			level.Load(levels[currentLevel]);
            this.CreateCharacters(level.SaveGame);
            this.ClearCollectables();

			this.timer = level.SaveGame.Timer;
			this.endTimer = 0;

			// Obstacles
			obstacles = new List<Obstacle>();
			// Creating walls
			foreach (Obstacle obstacle in this.level.ObstacleList)
			{
				this.obstacles.Add(obstacle);
			}

			// Collectables
			this.CreateCollectables(this.level.SaveGame.Collectables);

			currentLevel++;
		}

		/// <summary>
		/// Loads the level from save game.
		/// </summary>
		/// <param name="saveGame">The save game.</param>
		private void LoadLevel(SaveGame saveGame)
		{
            this.RemoveBodies();
            this.ClearOldCharacters();
			currentLevel = saveGame.Level;
			level.Load(levels[currentLevel]);
			this.CreateCharacters(saveGame);
			this.ClearCollectables();
			this.points = saveGame.Points;
			this.timer = saveGame.Timer;
			this.endTimer = 0;

			// Obstacles
			obstacles = new List<Obstacle>();
			// Creating walls
			foreach (Obstacle obstacle in this.level.ObstacleList)
			{
				this.obstacles.Add(obstacle);
			}

			// Collectables
			this.CreateCollectables(saveGame.Collectables);
			
			currentLevel++;
		}

		/// <summary>
		/// Checks the key for up & down positions (pressed on current update round).
		/// </summary>
		/// <param name="theKey">The key.</param>
		/// <returns>True, if key was pressed</returns>
		private bool CheckKey(Keys theKey)
		{
			return state.IsKeyDown(theKey) &&
				oldKeyState.IsKeyUp(theKey);
		}

		/// <summary>
		/// Draws the coordinates - just for level creation only.
		/// </summary>
		/// <param name="initialX">The initial X.</param>
		/// <param name="maxX">The max X.</param>
		/// <param name="initialY">The initial Y.</param>
		/// <param name="maxY">The max Y.</param>
		private void drawCoordinates(int initialX, int maxX, int initialY, int maxY)
		{
			// Ease for level making
			for (int i = initialY; i < maxY; i++)
			{
				for (int j = initialX; j < maxX; j++)
				{
					this.batch.DrawString(Content.Load<SpriteFont>("fonts/smallfont"), "[" + j + "," + i + "]", new Vector2(j + 7.6f - hero.Position.X, i + 6.4f - hero.Position.Y) * 64, Color.Blue);
	}
}
		}

	}
}
